package com.lingjtx.oss.common;

import com.lingjtx.common.core.model.api.OssUploadResponseItem;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;

@Service
public class ReactiveOSSService {

    @Value("${oss.bucket-name}")
    private String bucketName;

    @Value("${oss.file-url}")
    private String ossUrl;

    public Mono<OssUploadResponseItem> upload(Integer folderType, FilePart filePart) {
        String fileUri = AliyunOSSUtil.getFileUri(folderType, filePart.filename());

        return Mono.usingWhen(
                createTempFileAndWrite(filePart), // 创建并写入 temp 文件
                tempFile -> Mono.fromCallable(() -> {
                    try (InputStream inputStream = Files.newInputStream(tempFile)) {
                        boolean uploaded = AliyunOSSUtil.uploadFile(bucketName, fileUri, inputStream);
                        if (!uploaded) {
                            throw new RuntimeException("上传失败");
                        }
                        return new OssUploadResponseItem(fileUri, ossUrl + fileUri);
                    }
                }).subscribeOn(Schedulers.boundedElastic()), // 上传用阻塞线程池
                tempFile -> Mono.fromRunnable(() -> {
                    try {
                        Files.deleteIfExists(tempFile);
                    } catch (IOException e) {
                        // log.warn("无法删除临时文件: {}", tempFile, e);
                    }
                }) // 上传完毕后删除临时文件
        );
    }

    private Mono<Path> createTempFileAndWrite(FilePart filePart) {
        return Mono.fromCallable(() -> Files.createTempFile("upload-", filePart.filename()))
                .flatMap(tempFile ->
                        filePart.transferTo(tempFile.toFile())
                                .thenReturn(tempFile)
                );
    }
}
